package com.example.twoscroolview.view

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.graphics.plus
import kotlin.jvm.JvmOverloads
import android.graphics.PathMeasure


class FinishRelativeLayout : RelativeLayout {
    //鱼所在的ImageView
    private var ivFish: ImageView? = null

    //水波纹的半径, 属性动画底层原理就是反射调用setRipple方法
    var ripple = 0f
        set(value) {
            field = value
            System.out.println("field====$field")
            rippleAlpha = (100 * (1 - field)).toInt()
        }

    //水波纹的透明度
    var rippleAlpha = 0
    var mPaint = Paint()

    //触摸点
    var touchX = 0f
    var touchY = 0f

    val fishDrawable by lazy {
        FishDrawable()
    }

    constructor(context: Context) : super(context) {
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
    }

    init {
        init()
    }

    private fun init() {
        setWillNotDraw(false) //因为RelativeLayout默认不执行ondraw
        mPaint = Paint()
        mPaint?.isAntiAlias = true
        mPaint?.isDither = true
        mPaint.color = Color.RED
        mPaint.strokeWidth = 8f
        mPaint?.style = Paint.Style.STROKE
        ivFish = ImageView(context)
        val layoutParams =
            ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        ivFish?.layoutParams = layoutParams

        ivFish?.setImageDrawable(fishDrawable)
        addView(ivFish)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        mPaint.alpha = rippleAlpha
        canvas?.drawCircle(touchX, touchY, ripple * 150, mPaint)
        invalidate()
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        touchX = event?.x
        touchY = event?.y
        mPaint.alpha = 100
        val objectAnimator = ObjectAnimator.ofFloat(this, "ripple", 0f, 1f).setDuration(1000)
        objectAnimator.start()

        makeTrail()
        return super.onTouchEvent(event)
    }

    @SuppressLint("ObjectAnimatorBinding")
    private fun makeTrail() {
        // 鱼中/重心的相对坐标
        val fishRelative = fishDrawable.mMiddlePoint//鱼的重心坐标（中心 鱼游动转圈会根据这个值）
        val headRelative = fishDrawable.headPoint//   //鱼头圆心的点的坐标
        //鱼中/重心的绝对坐标， 起始点
        val fishMiddle =
            PointF(ivFish?.x!!.plus(fishRelative?.x!!), ivFish?.y!!.plus(fishRelative.y))
        // 鱼头的圆心控制点1，重心
        val fishHead =
            PointF(ivFish?.x!!.plus(headRelative.x), ivFish?.y!!.plus(headRelative.y))
        // 点击坐标 ，结束点
        val touch = PointF(touchX, touchY)
        val angle = includeAngle(fishMiddle, fishHead, touch) / 2  //重心和鱼头连线和重心和触摸点连线夹角的一半
        val delta = includeAngle(fishMiddle, PointF(fishMiddle.x + 1, fishMiddle.y), fishHead)     //重心和鱼头连线和x轴的夹角

        // 控制点2，angle + delta=触摸点和x轴的夹角
        val controlPoint = fishDrawable.calculatePoint(
            fishMiddle,
            fishDrawable.HEAD_RADIUS * 1.6f, angle + delta
        )
        val path = Path()
        path.moveTo(fishMiddle.x - fishRelative.x, fishMiddle.y - fishRelative.y)
        //绘制三阶贝塞尔曲线
        path.cubicTo(
            fishHead.x - fishRelative.x,
            fishHead.y - fishRelative.y,
            controlPoint.x - fishRelative.x,
            controlPoint.y - fishRelative.y,
            touchX - fishRelative.x,
            touchY - fishRelative.y
        )

        val animator = ObjectAnimator.ofFloat(ivFish, "x", "y", path)

        animator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                super.onAnimationEnd(animation)
                fishDrawable.frequence = fishDrawable.NOMAL_FREQUENCE
            }

            override fun onAnimationStart(animation: Animator?) {

                super.onAnimationStart(animation)
                fishDrawable.frequence = 11f
            }
        })

        //这里创建了一个PathMeasure对象。PathMeasure用于测量路径（由path参数指定）的长度、位置和切线等信息。第二个参数false表示不强制闭合路径进行测量。 如果路径是开放的，设置为false可以避免不必要的闭合操作。
        val pathMeasure = PathMeasure(path, false)
        //创建了一个长度为 2 的FloatArray，用于存储路径上某点的切线信息。在后续操作中，PathMeasure会将切线向量的 x 和 y 分量分别存储在这个数组中。
        val tan = FloatArray(2)
        //动画更新监听器：为动画对象（animator）添加了一个更新监听器。这个监听器会在动画的每一帧更新时被调用。
        animator.addUpdateListener(AnimatorUpdateListener { animation -> //                animation.getAnimatedValue();
            //获取动画进度分数：val fraction = animation.animatedFraction 获取当前动画执行的进度分数，范围是从 0（动画开始）到 1（动画结束）。
            val fraction = animation.animatedFraction
            //获取路径上的位置和切线信息：pathMeasure.getPosTan(pathMeasure.length * fraction, null, tan)根据动画进度分数计算在路径上的位置。
            //pathMeasure.length * fraction表示沿着路径的长度的相应位置。null参数表示不需要获取位置信息（如果需要位置信息，可以传入一个float数组来接收位置坐标）， tan数组用于接收切线信息。
            pathMeasure.getPosTan(pathMeasure.length * fraction, null, tan)
            //从tan数组中获取切线向量的 x 和 y 分量（tan[0]和tan[1]），然后使用Math.atan2函数计算切线向量的角度。由于atan2函数返回的是弧度值，所以使用Math.toDegrees将其转换为角度值，并将结果转换为float类型后存储在angle变量中。
            val angle = Math.toDegrees(
                Math.atan2(
                    (-tan[1]).toDouble(),
                    tan[0].toDouble()
                )
            ).toFloat()
            //最后，将计算得到的角度值赋给fishDrawable.mFishMainAngle，可能是用于更新鱼的绘制角度，使鱼沿着路径旋转。
            fishDrawable.mFishMainAngle = angle
        })


        animator.setDuration(2000)
        animator.start()
    }

    /**
     * 计算向量的夹角
     */
    fun includeAngle(O: PointF, A: PointF, B: PointF): Float {
        // cosAOB
        // OA*OB=(Ax-Ox)(Bx-Ox)+(Ay-Oy)*(By-Oy)
        val AOB = (A.x - O.x) * (B.x - O.x) + (A.y - O.y) * (B.y - O.y)
        val OALength =
            Math.sqrt(((A.x - O.x) * (A.x - O.x) + (A.y - O.y) * (A.y - O.y)).toDouble()).toFloat()
        // OB 的长度
        val OBLength =
            Math.sqrt(((B.x - O.x) * (B.x - O.x) + (B.y - O.y) * (B.y - O.y)).toDouble()).toFloat()
        val cosAOB = AOB / (OALength * OBLength)

        // Math.acos=反余弦，获取弧度，  Math.toDegrees=弧度转度数
        val angleAOB = Math.toDegrees(Math.acos(cosAOB.toDouble())).toFloat()

        // AB连线与X的夹角的tan值 - OB与x轴的夹角的tan值
        val direction = (A.y - B.y) / (A.x - B.x) - (O.y - B.y) / (O.x - B.x) //鱼转向的方向
        return if (direction == 0f) {
            if (AOB >= 0) {
                0f  //方向不变
            } else {
                180f //调头
            }
        } else {
            if (direction > 0) {
                -angleAOB //右侧顺时针
            } else {
                angleAOB//左侧逆时针
            }
        }
    }
}